/*
 Copyright 2005-2008 Lanlan Song <jackysonglanlan@gmail.com>

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
package jacky.lanlan.song.extension.struts;

import jacky.lanlan.song.extension.struts.annotation.*;
import jacky.lanlan.song.extension.struts.interceptor.*;
import jacky.lanlan.song.extension.struts.resource.Downloadable;
import jacky.lanlan.song.extension.struts.util.*;
import jacky.lanlan.song.extension.struts.util.bean.PropertyEditorManager;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.log4j.Logger;
import org.apache.struts.action.*;
import org.apache.struts.config.*;
import org.apache.struts.validator.*;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * <p>
 * 这个插件需要在 <code>struts-config.xml</code> 中配置：
 * <code>
		<pre>
			<plug-in className="jacky.lanlan.song.extension.struts.AnnotationConfigPlugIn">
		</pre>
	 </code>
 * </p>
 * <p>
 * 通过这个插件配置的ActionMapping，如果使用默认的 <code>URLMethodMapper</code>，将自动赋予每个Action默认的
 * 成功和失败Forward，规则如下：<br/>
 * <b style="color:red;font-size:12px;">
 * 默认成功Forward <br/>
 * name="success" 
 * path = <code>URLMethodMapper.DEFAULT</code> 生成的path，然后把'!'被替换为'_'，最后加上后缀"_success.jsp" <br/><br/>
 * 默认失败Forward <br/>
 * name="failure" 
 * path = <code>URLMethodMapper.DEFAULT</code> 生成的path，然后把'!'被替换为'_'，最后加上后缀"_failure.jsp" <br/><br/>
 * </b>
 * <p/>
 * 例如：对于<code>com.xxx.action.yyy.MyAction.foo()</code>方法，若设置<code>com.xxx.action</code>
 * 为 actionBasePackage，使用<code>URLMethodMapper.DEFAULT</code>作为路径映射器：
 * <p/>
 * <b style="color:green;font-size:12px;">
 * 默认成功Forward为:<br/>
 * <code>yyy_MyAction_foo_success.jsp</code><br/>
 * 默认失败Forward为:<br/>
 * <code>yyy_MyAction_foo_failure.jsp</code>
 * </b>
 * </p>
 * 可以提供一个URL到Action执行方法的映射器 <code>URLMethodMapper</code>，这个PlugIn将使用提供的
 * 映射器，以替代默认的 DEFAULT_MAPPER 来配置别名。
 * <p>
 * 另外，还可以通过使用@POJOAction，实现真正的POJO式的Action类。
 * </p>
 * @author Jacky.Song
 * @see URLMethodMapper.DEFAULT_MAPPER
 * @see jacky.lanlan.song.extension.struts.annotation.POJOAction
 */
public class AnnotationConfigPlugIn implements PlugIn {
	private final static Logger logger = Logger
			.getLogger(AnnotationConfigPlugIn.class);
	
	private String [] actionBasePackage;//标注配置的Action所在的根包路径
	
	private String actionURLSuffix;//触发action的url后缀(和ActionServlet的url-pattern指定的后缀相同)

	private Class<?> configClass;//配置类
	
	private URLMethodMapper urlMethodMapper = URLMethodMapper.DEFAULT;//映射器
	
	// POJO Action 执行方法缓存 [全类名 + '!' + 方法名 -> 对应的 Action 执行方法]
	private final ConcurrentMap<String, Method> actionMethodCache = 
		new ConcurrentHashMap<String, Method>(50);//默认50个

	// POJO Action 缓存 [Action 类 -> 对应的Action实例]
	private final ConcurrentMap<String, Object> actionCache = new ConcurrentHashMap<String, Object>(20);//默认20个

	private final Set<Class<? extends ActionForm>> formBeans= //所有的FormBean类
		new HashSet<Class<? extends ActionForm>>();

	// 拦截器链缓存，只对POJOAction进行拦截
	private final List<ActionInterceptor> interceptors = new ArrayList<ActionInterceptor> ();
	
	/**
	 * 设置调用action的URL后缀，应该和web.xml中ActionServlet的配置相同。
	 * <p>
	 * 默认为<i>.do</i>。
	 * @param actionURLSuffix
	 */
	public void setActionURLSuffix(String actionURLSuffix) {
		this.actionURLSuffix = actionURLSuffix;
	}
	
	/**
	 * 指定标注配置的Action所在包，插件将递归的寻找这个包及其子包下的所有有@Action标注的类，
	 * 即：用标注配置的Struts Action
	 * @param basePack 标注配置的Action所在包，如果有多个包，用<code>','</code>分割
	 */
	public void setActionBasePackage(String basePack) {
		this.actionBasePackage=basePack.split(",");
		for(String packName:actionBasePackage) {
			this.findCreateAndCacheActions(packName);
		}
	}
	//根据指定包，得到这个包及其子包下的所有有@Action标注的类(用标注配置的Struts Action)，然后创建并缓存
	private void findCreateAndCacheActions(String basePack){
		String problemClass=null;
		try {
			for (Class<?> actionClass : PackageUtils.findClassInPackage(basePack)) {
				problemClass=actionClass.getName();
				//过滤Action
				if(org.apache.struts.action.Action.class.isAssignableFrom(actionClass) ||//如果继承自Struts的Action
						actionClass.isAnnotationPresent(
								jacky.lanlan.song.extension.struts.annotation.Action.class) ||//或者有@Action标注
						actionClass.isAnnotationPresent(POJOAction.class)) {//或者有@POJOAction标注
					// 创建并缓存POJOAction，实现 Action 的Singleton语意 
					// TODO 通过Spring得到Action，Action名称从@POJO参数获取，实现Struts和Spring的无缝集成
					actionCache.put(actionClass.getName(), actionClass.newInstance());
				}
			}
		}
		catch (Exception e) {
			logger.error("缓存 Action [" + problemClass + "] 失败", e);
			throw new RuntimeException("缓存 Action [" + problemClass + "] 失败", e);
		}
	}

	/**
	 * 指定ActionInterceptor所在包，插件将递归的寻找这个包及其子包下的所有的ActionInterceptor。
	 * @param basePack ActionInterceptor 所在包，如果有多个包，用<code>','</code>分割
	 */
	public void setInterceptorBasePackage(String basePack) {
		for(String pack : basePack.split(",")) {
			//根据指定包，得到这个包及其子包下的所有的ActionInterceptor，然后创建并缓存
			PackageUtils.doWithClassInPackage(pack, new Handler<Class<?>>() {
				public void doWith(Class<?> interClass) {
					Class<?> errorInterceptor=null;
					try {
						if(ActionInterceptor.class.isAssignableFrom(interClass)) {
							interceptors.add((ActionInterceptor) interClass.newInstance());
						}
					}
					catch (Exception e) {
						logger.error("缓存拦截器 ["+errorInterceptor+"] 失败", e);
						throw new RuntimeException("缓存拦截器 ["+errorInterceptor+"] 失败", e);
					}
				}
			});
		}
	}
	
	private void addDefaultInterceptors(Collection<ActionInterceptor> interceptors) {
		interceptors.add(new DownloadInterceptor());
		interceptors.add(new CancellInterceptor());
		interceptors.add(new CleanInterceptor());
		interceptors.add(new UploadInterceptor());
	}
	
	/**
	 * 指定Form-Bean所在包，插件将递归的寻找这个包及其子包下的所有的ActionForm及其子类。
	 * @param basePack Form-Bean 所在包，如果有多个包，用<code>','</code>分割
	 */
	@SuppressWarnings("unchecked")
	public void setFormBeanBasePackage(String basePack) {
		for (String  pack : basePack.split(",")) {
			PackageUtils.doWithClassInPackage(pack, new Handler<Class<?>>() {
				public void doWith(Class<?> form) {
					if(ActionForm.class.isAssignableFrom(form)) {//如果继承自ActionForm
						formBeans.add((Class<? extends ActionForm>) form);
					}
				}
			});
		}
	}
	
	private void addDefaultFormBean(Collection<Class<? extends ActionForm>> classes) {
		classes.add(ActionForm.class);
		classes.add(DynaActionForm.class);
		classes.add(ValidatorForm.class);
		classes.add(DynaValidatorForm.class);
		classes.add(BeanValidatorForm.class);
		classes.add(LazyValidatorForm.class);
	}
	
	/**
	 * 指定 <code>PropertyEditor</code> 所在包。<br/>
	 * <code>PropertyEditor</code> 的命名需符合 JavaBean 规范。
	 * <p/>
	 * 这些 <code>PropertyEditor</code> 将用在{@link Form} 指定的 <code>ActionForm</code> 
	 * 的字符串值到 {@link Domain} 指定的领域对象的属性值之间的转换。
	 * @param pack 包名
	 */
	public void setPropertyEditorPackage(String pack) {
		PropertyEditorManager.setEditorSearchPath(new String []{pack});
		/*
		 * Sun默认的PropertyEditorManager写得真该死，会用注入的路径覆盖掉原来的默认路径，所以设置了自定义的路径后，
		 * 原来默认的String/Color/Font的Editor就找不到了。
		 * 根据这个类的API约定，默认包是无论如何也不该覆盖的，应该把自定义的路径添加到默认路径后面才是。
		 * 并且，通过自定义路径自动查到的PropertyEditor居然没有缓存，每次都要重新解析路径并创建PropertyEditor，以此来达到线程安全！
		 * 原来Sun的核心库里面也有这么该死的类 :(
		 */
	}
	
	/**
	 * 指定插件配置类。
	 * <p>
	 * 这个配置类用来配置Struts的全局属性，可以使用{@link GlobalForwards}和{@link GlobalExceptions}来标注一个
	 * 类，让它成为一个配置类。插件将读取上述标注的配置信息，以此来替代原来通过XML配置的相同信息。
	 * @param configClass 标注了{@link GlobalForwards}或{@link GlobalExceptions}的类
	 * @see GlobalForwards
	 * @see GlobalExceptions
	 */
	public void setConfigClass(String configClass) {
		try {
			Class<?> temp = Class.forName(configClass);
			for (Class<? extends Annotation> anno : new Class[] {GlobalExceptions.class,GlobalForwards.class}) {
				if(temp.isAnnotationPresent(anno)) {
					this.configClass=temp;
					return;
				}
			}
			throw new RuntimeException("配置类没有标注任何全局属性标注");
		}
		catch (ClassNotFoundException e) {
			logger.error("载入配置类时出错", e);
			throw new RuntimeException("载入配置类时出错", e);
		}
	}
	
	/**
	 * 指定URL到Action执行方法的映射器的路径。
	 * @param urlMethodMapper
	 */
	public void setUrlMethodMapper(String urlMethodMapper) {
		try {
			Class<?> mapper=Class.forName(urlMethodMapper);
			if(URLMethodMapper.class.isAssignableFrom(mapper)) {
				this.urlMethodMapper =(URLMethodMapper) mapper.newInstance();
			}
			else throw new IllegalArgumentException(
					urlMethodMapper+"没有实现"+URLMethodMapper.class);
		}
		catch (Exception e) {
			logger.error("载入"+urlMethodMapper+"时出错",e);
			throw new RuntimeException("载入"+urlMethodMapper+"时出错",e);
		}
	}
	
	public void init(ActionServlet servlet,ModuleConfig config){
		//配置全局设置
		this.configGlobals(config,this.configClass);
		
		//添加默认的ActionForm(struts 包里面的ActionForm及其子类)
		this.addDefaultFormBean(this.formBeans);
		
		//添加默认的拦截器
		this.addDefaultInterceptors(this.interceptors);

		//配置ActionForm
		this.configFormBeans(config,this.formBeans);
		
		//从Action里面提取所有的执行方法
		this.findAndCacheActionMethods(this.actionCache.values());
		
		//根据执行方法配置ActionMappings
		this.configActionMappings(config,this.actionMethodCache.values());
		
		//最关键的一步，把利用标注收集到的信息传递到POJOActionController，并装载入Struts
		this.preRegisterControllerToProcessor(servlet, config);
	}
	
	//预先注册POJOActionController到RequestProcessor (Struts默认为 lazy 方式)
	private void preRegisterControllerToProcessor(ActionServlet servlet,ModuleConfig config) {
		Map<String,Object> actionCacheInRP= // RequestProcessor的缓存设定:[全类名 -> 实例对象]
			this.getActionCacheInRequestProcessor(servlet, config);
		
		this.createAndRegController(servlet,actionCacheInRP);
	}
	
	@SuppressWarnings("unchecked")
	private Map<String,Object> getActionCacheInRequestProcessor(
			ActionServlet servlet,ModuleConfig config){
		/*
		 * 因为servlet没有暴露访问RequestProcessor的public接口，RequestProcessor也没有
		 * 暴露访问它缓存的Action的public接口，所以不能用通常的方法调用达到目的。
		 * 
		 * 这里用非常规的、类似黑客的办法，通过反射强行访问
		 */
		
		//////// 第1步，拿到servlet的RequestProcessor引用
		Method getMethod = ReflectionUtils.findMethod( 
				servlet.getClass(), "getRequestProcessor", new Class[] {ModuleConfig.class});
		
		getMethod.setAccessible(true);// 这个是protect方法，必须设置访问权限才能访问
		
		RequestProcessor processor=(RequestProcessor) ReflectionUtils.invokeMethod(
				getMethod, servlet, new Object[] {config});

		//////// 第2步，拿到RequestProcessor的Action缓存引用
		Field cacheField = ReflectionUtils.findField(RequestProcessor.class, "actions", HashMap.class);
		
		cacheField.setAccessible(true);//actions没有getter，只能通过Field直接访问,所以须设置访问权限
		
		try {
			return (Map) cacheField.get(processor);//Action缓存引用
		}
		catch (Exception e) {
			logger.error("访问 RequestProcessor 的 Action缓存 失败，查看 RequestProcessor 的缓存字段名是否是[actions]",e);
			throw new RuntimeException("致命错误",e);
		}
	}
	
	// 创建并注册Controller，这个过程本来是RequestProcessor来做，现在由Plugin掌握控制权，
	// 自己来做，这样就可以使用DI来配置POJOActionController
	private void createAndRegController(ActionServlet servlet,Map<String,Object> actionCacheInRP) {
		//////// 手动创建一个POJOActionController，并注入依赖项 
		POJOActionController controller=new POJOActionController();
		controller.setServlet(servlet);
		controller.setActionCache(actionCache);
		controller.setActionMethodCache(actionMethodCache);
		controller.setInterceptors(interceptors);
		/* TODO 注入 Spring ApplicationContext
		controller.setApplicationContext(
				WebApplicationContextUtils.getWebApplicationContext(servlet.getServletContext()));
		 */

		//////// 手动注册POJOActionController
		actionCacheInRP.put(POJOActionController.class.getName(), controller);
		//注意，缓存键一定要符合RequestProcessor的规定，否则RequestProcessor不能找到它，前面一切都白做
	}
	
	private void configGlobals(ModuleConfig config,Class<?> configClass) {
		//配置GlobalExceptions
		if(configClass.isAnnotationPresent(GlobalExceptions.class)) {
			LoggerUtils.debug(logger, "<---- 发现@GlobalExceptions，开始配置 Global Exception ---->");

			GlobalExceptions ge=configClass.getAnnotation(GlobalExceptions.class);
			int keyCount=ge.key().length;
			int typeCount=ge.type().length;
			int pathCount=ge.path().length;
			
			Assert.isTrue(keyCount==typeCount && typeCount==pathCount,
					GlobalExceptions.class+"配置错误：key/type/path 必须一一对应");
			
			boolean printOnce=false;
			for (int count = 0; count < ge.key().length; count++) {
				ExceptionConfig conf=new ExceptionConfig();
				conf.setKey(ge.key()[count]);
				conf.setType(ge.type()[count].getName());
				conf.setPath(ge.path()[count]);
				config.addExceptionConfig(conf);
				if(logger.isDebugEnabled()) {
					if(!printOnce) {
						logger.debug("=========== Successful register Global Exception ===========");
						printOnce=true;
					}
					else {
						logger.debug("------------------------------------------------------------");
					}
					logger.debug("key -> "+ge.key()[count]);
					logger.debug("type -> "+ge.type()[count].getName());
					logger.debug("path -> "+ge.path()[count]);
				}
			}
			logger.debug("============================================================");
			logger.debug("");
		}
		
		//配置GlobalForwards
		if(configClass.isAnnotationPresent(GlobalForwards.class)) {
			LoggerUtils.debug(logger, "<---- 发现@GlobalForwards，开始配置 Global Forward ---->");
			
			GlobalForwards gf=configClass.getAnnotation(GlobalForwards.class);

			Assert.isTrue(gf.name().length==gf.path().length,
					GlobalForwards.class+"配置错误：name/path 必须一一对应");
			
			boolean printOnce=false;
			for (int count = 0; count < gf.name().length; count++) {
				ForwardConfig conf=new ForwardConfig();
				conf.setName(gf.name()[count]);
				conf.setPath(gf.path()[count]);
				boolean redirect=false;
				if(gf.redirect().length-1>count) {//防止越界
					redirect=gf.redirect()[count];
				}
				conf.setRedirect(redirect);
				config.addForwardConfig(conf);
				if(logger.isDebugEnabled()) {
					if(!printOnce) {
						logger.debug("============ Successful register Global Forward ============");
						printOnce=true;
					}
					else {
						logger.debug("----------------------------------------------------------");
					}
					logger.debug("name -> "+gf.name()[count]);
					logger.debug("path -> "+gf.path()[count]);
				}
			}
			logger.debug("============================================================");
			logger.debug("");
		}
	}

	private void configFormBeans(ModuleConfig config, 
			Set<Class<? extends ActionForm>> classes) {
		LoggerUtils.debug(logger, "<---- 开始配置 Form Bean ---->");
		
		//配置Form-Beans
		boolean printOnce=false;
		for (Class<? extends ActionForm> formType : classes) {
			FormBeanConfig fbConf=new FormBeanConfig();
			fbConf.setName(formType.getName());//Form类名为Form名称
			fbConf.setType(formType.getName());//全限定名设置type，和XML的配置一样
			config.addFormBeanConfig(fbConf);
			if(logger.isDebugEnabled()) {
				if(!printOnce) {
					logger.debug("=============== Successful register Form Bean ==============");
					printOnce=true;
				}
				else {
					logger.debug("");
				}
				logger.debug("["+formType.getName()+" -> "+formType.getName()+"]");
			}
		}
		logger.debug("============================================================");
		logger.debug("");
	}
	
	//找到Action的所有执行方法，然后创建并缓存
	//得到通过标注配置的Struts Action方法
	private void findAndCacheActionMethods(Collection<Object> actions) {
		Class<?> actionClass=null;
		for (Object action : actions) {//遍历所有Action
			actionClass=action.getClass();
			for (Method execution : actionClass.getMethods()) {
				//收集所有的执行方法
				cacheExecution(execution,Execution.class,String.class);
				cacheExecution(execution,Download.class,Downloadable.class);
			}
		}
	}
	//缓存Action执行方法
	private void cacheExecution(Method execution,Class<? extends Annotation> anno,Class<?> returnType) {
		Class<?> actionClass=execution.getDeclaringClass();
		if(execution.isAnnotationPresent(anno)) {
			if(actionClass.isAnnotationPresent(POJOAction.class)) { //POJOAction 需要额外的检查
				if(execution.getReturnType()!=returnType || 
						!Arrays.equals(execution.getParameterTypes(),InfrastructureKeys.METHOD_PARAM)){
					throw new RuntimeException("方法 ["+execution+"] 签名不符合 ["+anno+"] 要求");
				}
			}
			this.actionMethodCache.put(actionClass.getName()+execution.getName(), execution);
		}
	}
	
	// 读取标注，并根据标注创建Struts需要的ActionMapping配置(原来写在xml里面的)
	private void configActionMappings(ModuleConfig config,Collection<Method> actionMethods) {
		LoggerUtils.debug(logger, "<---- 开始配置 Action Mapping ---->");
		
		try {
			boolean printOnce=false;
			for (Method actionMethod : actionMethods) {
				Class<?> actionClass = actionMethod.getDeclaringClass();
				final ActionConfig mapping = new ActionMapping();
				
				//设置默认值
				mapping.setType(actionClass.getName());
				mapping.setParameter(actionMethod.getName());// 设置Action的执行方法(Action是DispatchAction时有用)
				
				//如果是标注了@POJOAction
				if(actionClass.isAnnotationPresent(POJOAction.class)) {
					mapping.setType(POJOActionController.class.getName());//指派到POJOActionController
					//修改parameter来额外保存真正的Action类名
					mapping.setParameter(actionClass.getName()+"!"+actionMethod.getName());//格式:POJO Action的全类名!方法名
				}

				this.configMappingByMethod(actionMethod, mapping);
				
				config.addActionConfig(mapping);

				if (logger.isDebugEnabled()) {
					if(!printOnce) {
						logger.debug("============ Successful register ActionMapping ==============");
						printOnce=true;
					}
					else {
						logger.debug("-----------------------------------------------------------");
					}
					this.logMappingRegisteryInfo( mapping);
				}
			}
		}
		catch (final Exception e) {
			logger.error("Error while loading AnnotationConfigPlugIn: ", e);
			throw new RuntimeException(e);
		}
		logger.debug("=============================================================");
		logger.debug("");
	}
	private void configMappingByMethod(Method actionMethod,ActionConfig mapping) {
		
		/////////// establish defaults //////////
		String path = this.mapMethodToURL(actionMethod);
		String actionFormName = null;
		String input = null;
		String scope = "request";
		boolean validate = false;
		if(this.urlMethodMapper==URLMethodMapper.DEFAULT) {
			// 添加默认的页面路径
			this.addDefaultForward(mapping, path);
		}

		/////////// process annotations and override defaults where appropriate ////////////
    
		final Annotation[] annotations = actionMethod.getAnnotations();
		for (Annotation anno : annotations) {
			final Class<?> type = anno.annotationType();
			// 设置path属性
			if (type == Path.class) {
				path = ((Path) anno).value();
			}

			// 设置form
			else if (type == Form.class) {
				actionFormName = ((Form) anno).type().getName(); //name属性(Form类名，和注册名相同，否则不能找到这个Form - 见344行)
				validate = ((Form) anno).validate();// validate属性
			}

			// 设置forward属性
			else if (type == Forward.class) {
				final Forward fwd = (Forward) anno;
				this.regForwards(fwd, mapping);
			}

			// 设置成功页面Forward
			else if (type == SuccessTo.class) {
				SuccessTo st=(SuccessTo) anno;
				mapping.addForwardConfig(
					makeForward(st.name(), this.resolveForwardPath(st.path()), st.redirect())
				);
			}

			// 设置失败页面Forward
			else if (type == FailureTo.class) {
				FailureTo ft=(FailureTo) anno;
				mapping.addForwardConfig(
					makeForward(ft.name(), this.resolveForwardPath(ft.path()), ft.redirect())
				);
			}
			
			// 设置input属性
			else if (type == Input.class) {
				input = ((Input) anno).value();
			}
			
			// 设置scope属性
			if (type == InScope.class) {
				scope = ((InScope) anno).value();
			}

		}

		// use values
		mapping.setPath(path);
		mapping.setName(actionFormName);
		mapping.setInput(input);
		mapping.setScope(scope);
		mapping.setValidate(validate);
	}
	
	//添加默认的成功和失败Forward
	private void addDefaultForward(ActionConfig mapping, String path) {
		// 默认的成功页面路径
		mapping.addForwardConfig(makeForward(
				Forward.SUCCESS, path.replace('!', '_')+"_"+Forward.SUCCESS+".jsp"));
		// 默认的失败页面路径
		mapping.addForwardConfig(makeForward(
				Forward.FAILURE, path.replace('!', '_')+"_"+Forward.FAILURE+".jsp"));
	}
	
	private void logMappingRegisteryInfo(ActionConfig mapping) {
		logger.debug("URL Mapping:");
		logger.debug("Path [" + mapping.getPath() + "] -->");
		logger.debug("Action [" + mapping.getType()+ "] -->");
		logger.debug("Actual Method [" + mapping.getParameter().replace('!', '.')+"()]");
		logger.debug("");
		logger.debug("  name   -> " + mapping.getName());
		logger.debug("  input  -> " + mapping.getInput());
		logger.debug("  scope  -> " + mapping.getScope());
		logger.debug("validate -> " + mapping.getValidate());
		for(ForwardConfig fwd : mapping.findForwardConfigs()) {
			logger.debug("Forward [\"" + fwd.getName()+"\" -> "+fwd.getPath()+" redirect:"+fwd.getRedirect()+"]");
		}
	}
	
	//注册Forward
	private void regForwards(Forward fwd, ActionConfig mapping) {
		Assert.isTrue(fwd.name().length==fwd.path().length,
				Forward.class+"配置错误：name/path 必须一一对应");
		
		for (int count = 0; count < fwd.path().length; count++) {
			String name = fwd.name()[count];
			String path = this.resolveForwardPath(fwd.path()[count]);
			
			boolean fwdRedirect = false;
			if (fwd.redirect().length - 1 >= count) {//redirect因为不需要一一对应，所以需要检测个数，以免越界
				fwdRedirect = fwd.redirect()[count];
			}
			mapping.addForwardConfig(makeForward(name, path, fwdRedirect));
		}
	}
	//解析Forward的Path
	private String resolveForwardPath(String path) {
		String revoPath=path;
		if(path.startsWith("invoke:")) {//如果是一个调用语法，解析
			String [] str=path.substring(7).split("\\.");//str[0]是类名 str[1]是方法名
			for (Method m : this.actionMethodCache.values()) {//遍历所有执行方法
				if(m.getDeclaringClass().getSimpleName().equalsIgnoreCase(str[0]) &&//比较类名
						m.getName().equalsIgnoreCase(str[1])) {//再比较方法名
					revoPath=this.mapMethodToURL(m)+ //找到这个方法后，转换URL
								(this.actionURLSuffix==null?".do":this.actionURLSuffix);//后缀默认为.do
					break;
				}
			}
			if(revoPath==null) {
				throw new RuntimeException("无法解析调用语法 ["+path+"]");
			}
		}
		return revoPath;
	}
	
	//映射Action方法到URL
	private String mapMethodToURL(Method executionMethod) {
		//寻找最匹配该方法的basePackage
		String methodPackName=executionMethod.getDeclaringClass().getPackage().getName();
		String realBasePack=PackageUtils.findMostMatchPackage(this.actionBasePackage, methodPackName);
		
		return urlMethodMapper.mapMethodToURL(executionMethod,realBasePack);
	}
	
	/**
   * Helper method for creating ActionForwards,no redirect.
   * 
   * @param name
   *          Forward name.
   * @param path
   *          Registered path.
   * @return ForwardConfig.
   */
	private ForwardConfig makeForward(final String name, final String path) {
		return makeForward(name, path, false);
	}

	/**
   * Helper method for creating ActionForwards.
   * 
   * @param name
   *          Forward name.
   * @param path
   *          Registered path.
   * @param redirect
   *          Whether this should be an HTTP redirect.
   * @return ActionForward.
   */
	private ForwardConfig makeForward(final String name, final String path,
			final boolean redirect) {
		final ActionForward fc = new ActionForward();
		fc.setName(name);
		fc.setPath(path);
		fc.setRedirect(redirect);
		return fc;
	}

	public void destroy() {
		this.actionMethodCache.clear();
		this.actionCache.clear();
		this.formBeans.clear();
		this.interceptors.clear();
	}

}
